/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package GameModel.impl;

import GameModel.Board;
import GameModel.Field;
import GameModel.Figure;
import GameModel.GameModelPackage;

import GameModel.Helper.GameModelUtils;

import de.upb.tools.fca.*;

import de.upb.tools.sdm.*;

import java.lang.reflect.InvocationTargetException;

import java.util.*;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;

import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.InternalEList;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Board</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link GameModel.impl.BoardImpl#getSelectedField <em>Selected Field</em>}</li>
 *   <li>{@link GameModel.impl.BoardImpl#getFields <em>Fields</em>}</li>
 *   <li>{@link GameModel.impl.BoardImpl#getHeight <em>Height</em>}</li>
 *   <li>{@link GameModel.impl.BoardImpl#getWidth <em>Width</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class BoardImpl extends EObjectImpl implements Board {
	/**
	 * The cached value of the '{@link #getSelectedField() <em>Selected Field</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getSelectedField()
	 * @generated
	 * @ordered
	 */
	protected Field selectedField;

	/**
	 * The cached value of the '{@link #getFields() <em>Fields</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFields()
	 * @generated
	 * @ordered
	 */
	protected EList<Field> fields;

	/**
	 * The default value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected static final int HEIGHT_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected int height = HEIGHT_EDEFAULT;

	/**
	 * The default value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected static final int WIDTH_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected int width = WIDTH_EDEFAULT;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected BoardImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return GameModelPackage.Literals.BOARD;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Field getSelectedField() {
		if (selectedField != null && selectedField.eIsProxy()) {
			InternalEObject oldSelectedField = (InternalEObject) selectedField;
			selectedField = (Field) eResolveProxy(oldSelectedField);
			if (selectedField != oldSelectedField) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE,
							GameModelPackage.BOARD__SELECTED_FIELD,
							oldSelectedField, selectedField));
			}
		}
		return selectedField;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Field basicGetSelectedField() {
		return selectedField;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setSelectedField(Field newSelectedField) {
		Field oldSelectedField = selectedField;
		selectedField = newSelectedField;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					GameModelPackage.BOARD__SELECTED_FIELD, oldSelectedField,
					selectedField));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Field> getFields() {
		if (fields == null) {
			fields = new EObjectContainmentWithInverseEList<Field>(Field.class,
					this, GameModelPackage.BOARD__FIELDS,
					GameModelPackage.FIELD__BOARD);
		}
		return fields;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setHeight(int newHeight) {
		int oldHeight = height;
		height = newHeight;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					GameModelPackage.BOARD__HEIGHT, oldHeight, height));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setWidth(int newWidth) {
		int oldWidth = width;
		width = newWidth;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					GameModelPackage.BOARD__WIDTH, oldWidth, width));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Board initialize(GameModelUtils utils, int boardHeight,
			int boardWidth) {
		boolean fujaba__Success = false;
		Iterator fujaba__IterThisToBottom = null;
		Field bottom = null;
		Iterator fujaba__IterThisToLeft = null;
		Field left = null;
		Iterator fujaba__IterThisToRight = null;
		Field right = null;
		Iterator fujaba__IterThisToTop = null;
		Field top = null;
		Iterator fujaba__IterThisToNewField = null;
		Field newField = null;
		Iterator fujaba__IterThisToFields = null;
		Field fields = null;

		utils.addAllFields(this);
		// story pattern ActivityNode4
		try {
			fujaba__Success = false;

			// iterate to-many link fields from this to fields
			fujaba__Success = false;

			fujaba__IterThisToFields = new ArrayList(this.getFields())
					.iterator();

			while (fujaba__IterThisToFields.hasNext()) {
				try {
					fields = (Field) fujaba__IterThisToFields.next();

					// check object fields is really bound
					JavaSDM.ensure(fields != null);
					// story pattern ActivityNode2
					try {
						fujaba__Success = false;

						// iterate to-many link fields from this to newField
						fujaba__Success = false;

						fujaba__IterThisToNewField = this.getFields()
								.iterator();

						while (!(fujaba__Success)
								&& fujaba__IterThisToNewField.hasNext()) {
							try {
								newField = (Field) fujaba__IterThisToNewField
										.next();

								// check object newField is really bound
								JavaSDM.ensure(newField != null);
								// iterate to-many link fields from this to bottom
								fujaba__Success = false;

								fujaba__IterThisToBottom = this.getFields()
										.iterator();

								while (!(fujaba__Success)
										&& fujaba__IterThisToBottom.hasNext()) {
									try {
										bottom = (Field) fujaba__IterThisToBottom
												.next();

										// check optional
										if (bottom != null) {
											// check isomorphic binding between objects bottom and newField
											JavaSDM.ensure(!bottom
													.equals(newField));

											// attribute condition
											JavaSDM.ensure(bottom.getX() == newField
													.getX());

											// attribute condition
											JavaSDM.ensure(bottom.getY() == newField
													.getY() + 1);

										}
										fujaba__Success = true;
									} catch (JavaSDMException fujaba__InternalException) {
										fujaba__Success = false;
									}
								}
								if (!fujaba__Success) {
									fujaba__Success = true;
									bottom = null;
								}
								// iterate to-many link fields from this to left
								fujaba__Success = false;

								fujaba__IterThisToLeft = this.getFields()
										.iterator();

								while (!(fujaba__Success)
										&& fujaba__IterThisToLeft.hasNext()) {
									try {
										left = (Field) fujaba__IterThisToLeft
												.next();

										// check optional
										if (left != null) {
											// check isomorphic binding between objects left and newField
											JavaSDM.ensure(!left
													.equals(newField));

											// attribute condition
											JavaSDM.ensure(left.getX() == newField
													.getX() - 1);

											// attribute condition
											JavaSDM.ensure(left.getY() == newField
													.getY());

										}
										fujaba__Success = true;
									} catch (JavaSDMException fujaba__InternalException) {
										fujaba__Success = false;
									}
								}
								if (!fujaba__Success) {
									fujaba__Success = true;
									left = null;
								}
								// iterate to-many link fields from this to right
								fujaba__Success = false;

								fujaba__IterThisToRight = this.getFields()
										.iterator();

								while (!(fujaba__Success)
										&& fujaba__IterThisToRight.hasNext()) {
									try {
										right = (Field) fujaba__IterThisToRight
												.next();

										// check optional
										if (right != null) {
											// check isomorphic binding between objects right and newField
											JavaSDM.ensure(!right
													.equals(newField));

											// attribute condition
											JavaSDM.ensure(right.getX() == newField
													.getX() + 1);

											// attribute condition
											JavaSDM.ensure(right.getY() == newField
													.getY());

										}
										fujaba__Success = true;
									} catch (JavaSDMException fujaba__InternalException) {
										fujaba__Success = false;
									}
								}
								if (!fujaba__Success) {
									fujaba__Success = true;
									right = null;
								}
								// iterate to-many link fields from this to top
								fujaba__Success = false;

								fujaba__IterThisToTop = this.getFields()
										.iterator();

								while (!(fujaba__Success)
										&& fujaba__IterThisToTop.hasNext()) {
									try {
										top = (Field) fujaba__IterThisToTop
												.next();

										// check optional
										if (top != null) {
											// check isomorphic binding between objects top and newField
											JavaSDM.ensure(!top
													.equals(newField));

											// attribute condition
											JavaSDM.ensure(top.getX() == newField
													.getX());

											// attribute condition
											JavaSDM.ensure(top.getY() == newField
													.getY() - 1);

										}
										fujaba__Success = true;
									} catch (JavaSDMException fujaba__InternalException) {
										fujaba__Success = false;
									}
								}
								if (!fujaba__Success) {
									fujaba__Success = true;
									top = null;
								}

								fujaba__Success = true;
							} catch (JavaSDMException fujaba__InternalException) {
								fujaba__Success = false;
							}
						}
						JavaSDM.ensure(fujaba__Success);
						// check optional
						if (right != null) {
							// create link
							org.moflon.util.eMoflonEMFUtil
									.addOppositeReference(newField, right,
											"right");
						}// check optional
						if (bottom != null) {
							// create link
							org.moflon.util.eMoflonEMFUtil
									.addOppositeReference(newField, bottom,
											"bottom");
						}// check optional
						if (left != null) {
							// create link
							org.moflon.util.eMoflonEMFUtil
									.addOppositeReference(newField, left,
											"left");
						}// check optional
						if (top != null) {
							// create link
							org.moflon.util.eMoflonEMFUtil
									.addOppositeReference(newField, top, "top");
						}
						fujaba__Success = true;
					} catch (JavaSDMException fujaba__InternalException) {
						fujaba__Success = false;
					}

					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}
			}
			JavaSDM.ensure(fujaba__Success);
			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		return this;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getBoardSize() {
		boolean fujaba__Success = false;

		return this.height + this.width;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Board fieldSelected(Field field) {
		boolean fujaba__Success = false;
		Field selField = null;
		Figure selFigure = null;
		Figure figure = null;

		// story pattern ActivityNode10
		try {
			fujaba__Success = false;

			// bind object
			selField = this.getSelectedField();

			// check object selField is really bound
			JavaSDM.ensure(selField != null);

			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		if (fujaba__Success) {
			// story pattern ActivityNode11
			try {
				fujaba__Success = false;

				// check object selField is really bound
				JavaSDM.ensure(selField != null);
				// bind object
				selFigure = selField.getFigure();

				// check object selFigure is really bound
				JavaSDM.ensure(selFigure != null);

				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

			selFigure.moveTo(field);
			// story pattern ActivityNode13
			try {
				fujaba__Success = false;

				// check object selField is really bound
				JavaSDM.ensure(selField != null);
				// check link selectedField from this to selField
				JavaSDM.ensure(selField.equals(this.getSelectedField()));

				// destroy link
				org.moflon.util.eMoflonEMFUtil.removeOppositeReference(this,
						selField, "selectedField");
				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

		} else {
			// story pattern ActivityNode8
			try {
				fujaba__Success = false;

				// check object field is really bound
				JavaSDM.ensure(field != null);
				// bind object
				figure = field.getFigure();

				// check object figure is really bound
				JavaSDM.ensure(figure != null);

				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

			// story pattern ActivityNode9
			try {
				fujaba__Success = false;

				// check object field is really bound
				JavaSDM.ensure(field != null);
				// create link
				org.moflon.util.eMoflonEMFUtil.addOppositeReference(this,
						field, "selectedField");
				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

		}
		return this;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public NotificationChain eInverseAdd(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case GameModelPackage.BOARD__FIELDS:
			return ((InternalEList<InternalEObject>) (InternalEList<?>) getFields())
					.basicAdd(otherEnd, msgs);
		}
		return super.eInverseAdd(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case GameModelPackage.BOARD__FIELDS:
			return ((InternalEList<?>) getFields()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
		case GameModelPackage.BOARD__SELECTED_FIELD:
			if (resolve)
				return getSelectedField();
			return basicGetSelectedField();
		case GameModelPackage.BOARD__FIELDS:
			return getFields();
		case GameModelPackage.BOARD__HEIGHT:
			return getHeight();
		case GameModelPackage.BOARD__WIDTH:
			return getWidth();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
		case GameModelPackage.BOARD__SELECTED_FIELD:
			setSelectedField((Field) newValue);
			return;
		case GameModelPackage.BOARD__FIELDS:
			getFields().clear();
			getFields().addAll((Collection<? extends Field>) newValue);
			return;
		case GameModelPackage.BOARD__HEIGHT:
			setHeight((Integer) newValue);
			return;
		case GameModelPackage.BOARD__WIDTH:
			setWidth((Integer) newValue);
			return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
		case GameModelPackage.BOARD__SELECTED_FIELD:
			setSelectedField((Field) null);
			return;
		case GameModelPackage.BOARD__FIELDS:
			getFields().clear();
			return;
		case GameModelPackage.BOARD__HEIGHT:
			setHeight(HEIGHT_EDEFAULT);
			return;
		case GameModelPackage.BOARD__WIDTH:
			setWidth(WIDTH_EDEFAULT);
			return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
		case GameModelPackage.BOARD__SELECTED_FIELD:
			return selectedField != null;
		case GameModelPackage.BOARD__FIELDS:
			return fields != null && !fields.isEmpty();
		case GameModelPackage.BOARD__HEIGHT:
			return height != HEIGHT_EDEFAULT;
		case GameModelPackage.BOARD__WIDTH:
			return width != WIDTH_EDEFAULT;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eInvoke(int operationID, EList<?> arguments)
			throws InvocationTargetException {
		switch (operationID) {
		case GameModelPackage.BOARD___INITIALIZE__GAMEMODELUTILS_INT_INT:
			return initialize((GameModelUtils) arguments.get(0),
					(Integer) arguments.get(1), (Integer) arguments.get(2));
		case GameModelPackage.BOARD___GET_BOARD_SIZE:
			return getBoardSize();
		case GameModelPackage.BOARD___FIELD_SELECTED__FIELD:
			return fieldSelected((Field) arguments.get(0));
		}
		return super.eInvoke(operationID, arguments);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy())
			return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (height: ");
		result.append(height);
		result.append(", width: ");
		result.append(width);
		result.append(')');
		return result.toString();
	}

} //BoardImpl
